/*
 * Copyright (c) 2021
 * User:魔金多商户商城
 * File:YunUploadUtils.java
 * Date:2021/01/16 18:57:16
 */

package com.ruoyi.common.utils;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.utils.bean.OssSetting;
import com.ruoyi.common.utils.bean.OssYunConf;
import com.ruoyi.common.utils.file.FileUtils;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by 魔金商城 on 17/5/8.
 * 又拍云上传工具
 */
@Slf4j
public class YunUploadUtils {

    private static final YunUploadUtils INSTANCE = new YunUploadUtils();
    /**
     * 调试工具
     */
    private Logger logger = LoggerFactory.getLogger(YunUploadUtils.class);
    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
    // 文件存储目录
    private String filedir = "";

    private YunUploadUtils() {
    }

    public static YunUploadUtils getInstance() {
        return INSTANCE;
    }

    /**
     * Description: 判断OSS服务文件上传时文件的contentType
     *
     * @param
     * @return String
     */
    public static String getcontentType(String filenameExtension) {
        if ("bmp".equalsIgnoreCase(filenameExtension)) {
            return "image/bmp";
        }
        if ("gif".equalsIgnoreCase(filenameExtension)) {
            return "image/gif";
        }
        if ("jpeg".equalsIgnoreCase(filenameExtension) || "jpg".equalsIgnoreCase(filenameExtension)
                || "png".equalsIgnoreCase(filenameExtension)) {
            return "image/jpeg";
        }
        if ("html".equalsIgnoreCase(filenameExtension)) {
            return "text/html";
        }
        if ("txt".equalsIgnoreCase(filenameExtension)) {
            return "text/plain";
        }
        if ("vsd".equalsIgnoreCase(filenameExtension)) {
            return "application/vnd.visio";
        }
        if ("pptx".equalsIgnoreCase(filenameExtension) || "ppt".equalsIgnoreCase(filenameExtension)) {
            return "application/vnd.ms-powerpoint";
        }
        if ("docx".equalsIgnoreCase(filenameExtension) || "doc".equalsIgnoreCase(filenameExtension)) {
            return "application/msword";
        }
        if ("xml".equalsIgnoreCase(filenameExtension)) {
            return "text/xml";
        }
        return "image/jpeg";
    }

    /**
     * 获取文件保存路径
     *
     * @param fileOriginName 用户上传文件名
     * @return 文件保存路径
     */
    private String getFilePath(String fileOriginName) {
        String fileType = "jpg";
        if (!StringUtils.isEmpty(fileOriginName) && fileOriginName.contains(".")) {
            fileType = fileOriginName.substring(fileOriginName.lastIndexOf(".") + 1);
        }
        String fileName = String.valueOf(System.currentTimeMillis()) + "." + fileType;
        String date = simpleDateFormat.format(Calendar.getInstance(TimeZone.getTimeZone("GMT+08:00")).getTime());
        return "/" + date + "/" + fileName;
    }

    /**
     * 判断是否是图片
     *
     * @param bytes 字节数组
     * @return 是图片返回true  否则返回false
     */
    private boolean isPicture(byte[] bytes) {
        try {
            BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes));
            return image != null;
        } catch (IOException e) {
            logger.error("file is not a picture ...", e);
            return false;
        }
    }

    /**
     * 上传腾讯云
     *
     * @param file
     * @param bytes 图片字节
     * @param type  上传的类型 0 图片 1 视频
     * @return 返回图片在又拍云的地址
     */
    public String uploadToQqOss(OssYunConf cloudStorageConfig, MultipartFile file, byte[] bytes, String fileOriginName, String type) {
        return QqOssClient.uploadToQqOss(cloudStorageConfig, file, bytes, fileOriginName, type);
    }

    public String uploadToMinio(MultipartFile multipartFile, OssSetting ossSetting) {
        String bukeet = "mojin";
// http://51wangshi.com:8099 minioadmin
        MinioClient minioClient = new MinioClient("http://51wangshi.com:8099", "minioadmin", "minioadmin");
        // bukeet = ossSetting.getBucketName();
        String url = "";
        String oldName = multipartFile.getOriginalFilename();
        //获取扩展名，默认是jpg
        String picExpandedName = FileUtils.getPicExpandedName(oldName);
        //获取新文件名
        String newFileName = System.currentTimeMillis() + "." + picExpandedName;
        try {
            boolean isExist = minioClient.bucketExists(bukeet);
            if (!isExist) {
                minioClient.makeBucket(bukeet);
            }
            // 重新生成一个文件名
            InputStream inputStram = multipartFile.getInputStream();
            minioClient.putObject(
                    PutObjectArgs.builder().bucket(bukeet).object(newFileName).stream(
                            inputStram, multipartFile.getSize(), -1)
                            .contentType(multipartFile.getContentType())
                            .build());
            url = "/" + bukeet + "/" + newFileName;
            return minioClient.presignedGetObject(bukeet, newFileName);
        } catch (Exception e) {
            e.getStackTrace();
            log.error("上传文件出现异常: {}", e.getMessage());
        }
        return url;
    }

    /**
     * 上传又拍云
     *
     * @param upYunConf   又拍云设置
     * @param inputStream 输入流
     * @param bytes       图片字节
     * @return 返回图片在又拍云的地址
     */
    public String uploadToQqForBase64(OssYunConf upYunConf, InputStream inputStream, byte[] bytes, String fileOriginName) {
        logger.debug("Being to uploadToUpYun.....");
        if (org.apache.commons.lang3.ArrayUtils.isEmpty(bytes)) {
            logger.error("uploadToUpYun fail due to bytes is empty ....");
            return "";
        }
        return null;
    }

    /**
     * 上传阿里云
     *
     * @param inputStream 输入流
     * @param bytes       图片字节
     * @param type        上传的类型 0 图片 1 视频
     * @return 返回图片在又拍云的地址
     */
    public String uploadToOssYun(OssYunConf config, InputStream inputStream, byte[] bytes, String fileOriginName, String type) {
        String url = null;
        try {
            url = upload(config.getAccessKeyId(), config.getAccessKeySecret(), config.getBucketName(), config.getEndPoint(),
                    config.getPrefix(), getKey(config.getBucketName(), ""), inputStream, fileOriginName);

        } catch (Exception e) {
            return e.getMessage();
        }
        return url;
    }

    /**
     * 上传又拍云
     *
     * @param inputStream 输入流
     * @param bytes       图片字节
     * @return 返回图片在又拍云的地址
     */
    public String uploadToOssYunForBase64(OssYunConf config, InputStream inputStream, byte[] bytes, String fileOriginName) {
        String url = null;
        try {
            url = upload(config.getAccessKeyId(), config.getAccessKeySecret(), config.getBucketName(), config.getEndPoint(),
                    config.getPrefix(), getKey(config.getBucketName(), ""), inputStream, fileOriginName);

        } catch (Exception e) {
            return e.getMessage();
        }
        return url;
    }

    /**
     * 上传文件<>基础方法</>
     *
     * @param accessKeyId     授权 ID
     * @param accessKeySecret 授权密钥
     * @param bucketName      桶名
     * @param endpoint        节点名
     * @param styleName       样式名
     * @param key             文件名
     * @param inputStream     文件流
     * @return 访问路径 ，结果为null时说明上传失败
     */
    public String upload1(String accessKeyId, String accessKeySecret, String bucketName, String endpoint, String
            styleName, String key, InputStream inputStream) {
        if (inputStream == null) {
            return null;
        }
        String url = null;
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        try {
            // 带进度条的上传
            ossClient.putObject(new PutObjectRequest(bucketName, key, inputStream));
        } catch (OSSException oe) {
            oe.printStackTrace();
            key = null;
        } catch (ClientException ce) {
            ce.printStackTrace();
            key = null;
        } catch (Exception e) {
            e.printStackTrace();
            key = null;
        } finally {
            ossClient.shutdown();
        }
        if (key != null) {
            // 拼接文件访问路径。由于拼接的字符串大多为String对象，而不是""的形式，所以直接用+拼接的方式没有优势
            StringBuffer sb = new StringBuffer();
            sb.append("http://").append(bucketName).append(".").append(endpoint).append("/").append(key);
            if (StringUtils.isNotBlank(styleName)) {
                sb.append("/").append(styleName);
            }
            url = sb.toString();
        }
        return url + ".png";
    }

    /**
     * 上传文件<>基础方法</>
     *
     * @param accessKeyId     授权 ID
     * @param accessKeySecret 授权密钥
     * @param bucketName      桶名
     * @param endpoint        节点名
     * @param styleName       样式名
     * @param key             文件名
     * @param inputStream     文件流
     * @return 访问路径 ，结果为null时说明上传失败
     */
    public String upload(String accessKeyId, String accessKeySecret, String bucketName, String endpoint, String
            styleName, String key, InputStream inputStream, String fileOriginName) {
        if (inputStream == null) {
            return null;
        }
        String substring = fileOriginName.substring(fileOriginName.lastIndexOf(".")).toLowerCase();
        Random random = new Random();
        String name = random.nextInt(10000) + System.currentTimeMillis() + substring;
        try {

            return this.uploadFile2OSS(inputStream, name, accessKeyId, accessKeySecret, bucketName, endpoint,
                    styleName, key);

        } catch (Exception e) {

        }
        return name;

    }

    /**
     * 获取文件名（bucket里的唯一key）
     * 上传和删除时除了需要bucketName外还需要此值
     *
     * @param prefix 前缀（非必传），可以用于区分是哪个模块或子项目上传的文件
     * @param suffix 后缀（非必传）, 可以是 png jpg 等
     * @return
     */
    public String getKey(final String prefix, final String suffix) {
        //生成uuid,替换 - 的目的是因为后期可能会用 - 将key进行split，然后进行分类统计
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        //文件路径
        String path = DateUtils.parseDateToStr("yyyyMMdd", new Date()) + "-" + uuid;

        if (StringUtils.isNotBlank(prefix)) {
            path = prefix + "-" + path;
        }
        if (suffix != null) {
            if (suffix.startsWith(".")) {
                path = path + suffix;
            } else {
                path = path + "." + suffix;
            }
        }
        return path;
    }

    /**
     * 上传图片
     *
     * @param url
     * @throws CustomException
     */
    public void uploadImg2Oss(String accessKeyId, String accessKeySecret, String bucketName, String endpoint, String
            styleName, String key, String url) throws CustomException {
        File fileOnServer = new File(url);
        FileInputStream fin;
        try {
            fin = new FileInputStream(fileOnServer);
            String[] split = url.split("/");
            this.uploadFile2OSS(fin, split[split.length - 1], accessKeyId, accessKeySecret, bucketName, endpoint,
                    styleName, key);
        } catch (FileNotFoundException e) {
            throw new CustomException("图片上传失败");
        }
    }

    public String uploadImg2Oss(String accessKeyId, String accessKeySecret, String bucketName, String endpoint, String
            styleName, String key, MultipartFile file) throws CustomException {
        if (file.getSize() > 10 * 1024 * 1024) {
            throw new CustomException("上传图片大小不能超过10M！");
        }
        String originalFilename = file.getOriginalFilename();
        String substring = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();
        Random random = new Random();
        String name = random.nextInt(10000) + System.currentTimeMillis() + substring;
        try {
            InputStream inputStream = file.getInputStream();
            this.uploadFile2OSS(inputStream, name, accessKeyId, accessKeySecret, bucketName, endpoint,
                    styleName, key);
            return name;
        } catch (Exception e) {
            throw new CustomException("图片上传失败");
        }
    }

    /**
     * 上传到OSS服务器 如果同名文件会覆盖服务器上的
     *
     * @param instream 文件流
     * @param fileName 文件名称 包括后缀名
     * @return 出错返回"" ,唯一MD5数字签名
     */
    public String uploadFile2OSS(InputStream instream, String fileName, String accessKeyId, String accessKeySecret, String bucketName, String endpoint, String
            styleName, String key) {
        String ret = "";
        try {
            OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
            // 创建上传Object的Metadata
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(instream.available());
            objectMetadata.setCacheControl("no-cache");
            objectMetadata.setHeader("Pragma", "no-cache");
            objectMetadata.setContentType(getcontentType(fileName.substring(fileName.lastIndexOf("."))));
            objectMetadata.setContentDisposition("inline;filename=" + fileName);
            // 上传文件
            PutObjectResult putResult = ossClient.putObject(bucketName, filedir + fileName, instream, objectMetadata);
            ret = putResult.getETag();
            return "http://" + bucketName + "." + endpoint + "/" + filedir + fileName;

        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        } finally {
            try {
                if (instream != null) {
                    instream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return "";
    }


}
